// ValidationAspects
// Written by Mike Saunders
// Released under Microsoft Public License (Ms-PL)
using System;
using NUnit.Framework;
using ValidationAspects;
using ValidationAspects.Core;
using ValidationAspects.Sdk;

namespace TestValidationAspects.Sdk
{
	[TestFixture]
	public class TestAdapt
	{
		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Test_From_throws_for_null_param()
		{
			Adapt<Derived, Base>.From(null);
		}

		[Test]
		public void Test_From_returns_a_ValidatorAdaptor()
		{
			BaseValidator baseValidator = new BaseValidator();
			IValidator<Derived> validator = Adapt<Derived, Base>.From(baseValidator);
			Assert.AreSame(typeof(ValidatorAdaptor<Derived, Base>), validator.GetType());

			validator.Invoke(new Derived(), new MockValidationContext());

			Assert.IsTrue(baseValidator.WasCalled);
		}

		[Test]
		public void Test_usage_in_factory_Create()
		{
			BaseValidatorFactory factory = new BaseValidatorFactory();

			typeof(Derived).ReplaceValidation(new[] {factory});

			Derived value = new Derived();
			IValidationContext context = new MockValidationContext();
			typeof(Derived).ResolveValidator().Invoke(value, context);

			Assert.AreSame(value, factory.Value);
			Assert.AreSame(context, factory.Context);
		}

		#region Mocks
		public class Base {}

		public class Derived : Base {}

		public class BaseValidator : IValidator<Base>
		{
			public bool WasCalled { get; set; }

			#region Implementation of IValidator
			public void Invoke(Base value, IValidationContext context)
			{
				WasCalled = true;
			}

			public void Invoke(object value, IValidationContext context)
			{
				throw new NotImplementedException();
			}
			#endregion
		}

		public class BaseValidatorFactory : IValidatorFactory
		{
			public Base Value { get; set; }
			public object Context { get; set; }

			#region Implementation of IValidatorFactory
			public IValidator<T> Create<T>()
			{
				return Adapt<T, Base>.From(new Validator<Base>((v, c) =>
				                                               {
				                                               	Value = v;
				                                               	Context = c;
				                                               }));
			}
			#endregion
		}
		#endregion
	}
}